/*******************************************************************************
* Copyright 2007-2013 See AUTHORS file.
 * 
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* 
*   http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.xmeta.util;

import java.util.logging.Logger;

import org.xmeta.ActionException;
import org.xmeta.Thing;
import org.xmeta.World;


public class UtilThing {
	//private static Logger logger = LoggerFactory.getLogger(UtilThing.class);
	private static Logger logger = Logger.getLogger(UtilThing.class.getName());
	
	/**
	 * 通过模型属性获取模型定义的模型，或者通过指定的子模型的第一个子节点获取定义的模型。
	 * 
	 * @param thing 模型
	 * @param attributeName 属性名
	 * @param childThingPath 子模型路径
	 * @return 模型
	 */
	public static Thing getThingFromAttributeOrChilds(Thing thing, String attributeName, String childThingPath){
		Thing t = null;
		
		String attrValue = thing.getString(attributeName);
		if(attrValue != null && !"".equals(attrValue)){
			t = World.getInstance().getThing(attrValue);
		}
		
		if(t == null){
			t = thing.getThing(childThingPath);
			if(t != null && t.getChilds().size() > 0){
				t = t.getChilds().get(0);
			}else{
				t = null;
			}
		}
		
		return t;
	}
	
	/**
	 * 通过模型属性获取模型定义的模型，或者通过指定的子模型的第一个子节点获取定义的模型。
	 * 
	 * @param thing 模型
	 * @param attributeName 属性名
	 * @param childThingPath 子模型路径
	 * @return 模型
	 */
	public static Thing getThingFromAttributeOrChild(Thing thing, String attributeName, String childThingPath){
		Thing t = null;
		
		String attrValue = thing.getString(attributeName);
		if(attrValue != null && !"".equals(attrValue)){
			t = World.getInstance().getThing(attrValue);
		}
		
		if(t == null){
			return thing.getThing(childThingPath);
		}
		
		return t;
	}
	
	/**
	 * 判断一个模型作为描述者时是否是给定的类型，即判断这个模型的路径以及所有继承模型的路径是否是指定的descritpor。
	 * 
	 * @param descriptorThing 描述者模型
	 * @param descriptor 描述者
	 * @return 是否
	 */
	public static boolean isDescriptorEquals(Thing descriptorThing, String descriptor){
		if(descriptorThing == null){
	        return false;
	    }
	    
	    if(descriptorThing.getMetadata().getPath().equals(descriptor)){
	        return true;
	    }
	    
	    for(Thing ext : descriptorThing.getAllExtends()){
	        if(ext.getMetadata().getPath().equals(descriptor)){
	            return true;
	        }
	    }
	    
	    return false;
	}
	
	public static boolean isDescriptorEquals1(String descriptorFor, String descriptor){
		return isDescriptorEquals(World.getInstance().getThing(descriptorFor), descriptor);
	}
	
	/**
	 * 获取模型，如果不存在就创建一个。
	 * 
	 * @param path 路径
	 * @param thingManager 模型管理器
	 * @param descriptorForCreate 描述者
	 * @return 模型
	 */
	public static Thing getThingIfNotExistsCreate(String path, String thingManager, String descriptorForCreate){
		Thing thing = World.getInstance().getThing(path);
		if(thing == null){
			thing = new Thing(descriptorForCreate);
			if(World.getInstance().getThingManager(thingManager)!= null) {				
				thing.saveAs(thingManager, path);
			}else {
				logger.info("Can not crate thing=" + path + ", thingManager=" + thingManager + " not exists");
			}
		}
		
		return thing;
	}
	
	/**
	 * 获取模型，如果不存在就用已有的模型创建一个。
	 * 
	 * @param path 路径
	 * @param thingManager 模型管理器
	 * @param forReplace 是否覆盖
	 * @return 模型
	 */
	public static Thing getThingIfNotExistsCreate(String path, String thingManager, Thing forReplace){
		Thing thing = World.getInstance().getThing(path);
		if(thing == null){
			thing = forReplace.detach();
			if(World.getInstance().getThingManager(thingManager) != null) {
				thing.saveAs(thingManager, path);
			}else {
				logger.info("Can not crate thing=" + path + ", thingManager=" + thingManager + " not exists");
			}
		}
		
		return thing;
	}
	
	/**
	 * 返回引用的模型，如果属性就不存在，那么就找根模型下的子模型。如果是子模型，那么替换路径。
	 * 
	 * @param thing
	 * @param attribute
	 * @return
	 */
	public static Thing getQuoteThing(Thing thing, String attribute){
		String path = thing.getStringBlankAsNull(attribute);
		if(path == null){
			return null;
		}
		
		World world = World.getInstance();
		Thing qthing = world.getThing(path);
		if(qthing == null){			
			int index = path.indexOf("/@");
			if(index != -1){
				Thing root = thing.getRoot();
				path = root + path.substring(index, path.length());
				qthing = world.getThing(path);
				if(qthing != null){
					thing.set(attribute, path);
				}
			}
		}
		
		return qthing;
	}
	
	/**
	 * 返回只会连接到同一个根模型下的子模型，用在只会在模型内部连接的情况。
	 * 
	 * @param thing 模型
	 * @param attribute 改模型的属性名
	 * 
	 * @return 所连接的模型
	 */
	public static Thing getSelfQuoteThing(Thing thing, String attribute){
		String path = thing.getStringBlankAsNull(attribute);
		if(path == null){
			return null;
		}
		
		Thing root = thing.getRoot();
		if("_root".equals(path)){
			return root;
		}
		
		if("_parent".equals(path)){
			return thing.getParent();
		}
		
		World world = World.getInstance();
		if(path.startsWith(root.getMetadata().getPath() + "/@")){
			//本身就是自己的连接
			return world.getThing(path);
		}else{
			int index = path.indexOf("/@");
			if(index == -1){
				return root;
			}else{
				path = root.getMetadata().getPath() + path.substring(index, path.length());
				Thing qthing = world.getThing(path);
				if(qthing != null){
					thing.set(attribute, path);
				}
				
				return qthing;
			}
		}		
	}
	
	/**
	 * 改变一个模型的编码格式。
	 * 
	 * @param thing
	 * @param coder
	 */
	public static void changeCoder(Thing thing, String coder){
		if(coder != null && !coder.equals(thing.getMetadata().getCoderType())){
			if(World.getInstance().getThingCoder(coder) == null){
				throw new ActionException("Thing coder not exists, type=" + coder);
			}
			
			thing = thing.getRoot();
			
			//先删除原有模型，这样可以从文件中删除，然后再保存
			thing.remove();
			
			thing.getMetadata().setCoderType(coder);
			thing.save();
		}
	}
}